<?php
/**
 * Mysql database interaction class for WLP library
 *
 * This files contains the class for  Mysql database interaction with
 * WLP's library of classes.
 *
 * @author David Stangeby <david.stangeby@gmail.com>
 * @version 0.1
 * @package WLP
 * @copyright  Copyright (c) 2005-2009 Arctic Solutions (http://www.arcticsolutions.no/)
 * @license    http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt GNU General Public License v2
 */

/**
 * Include the WLP_Db_Interface interface file.
 */
require_once(dirname(__FILE__) . '/Interface.php');

/**
 * Class for Mysql database interaction for WLP.
 *
 * @package WLP
 */
class WLP_Db_Mysql implements WLP_Db_Interface
{
    /**
     * Hostname to be used for the Mysql connection.
     * @var string
     */
    protected $hostname = '';
    
    /**
     * Username to be used for the Mysql connection.
     * @var string
     */
    protected $username = '';
    
    /**
     * Password to be used for the Mysql connection.
     * @var string
     */
    protected $password = '';
    
    /**
     * Database to be used for the Mysql connection.
     * @var string
     */
    protected $database = '';
    
    /**
     * PDO handle for interaction with the Mysql database.
     * @var PDO
     */
    protected $pdo;
    
    /**
     * PDO statement handle used with perpared statements.
     * @var PDOStatement
     */
    protected $statement;
    
        /**
     * Constructor
     *
     * Sets options for the class, usually connetion information to the database.
     *
     * @param array $options Array of options to be set for the class
     * @return void
     */
    public function __construct($options = null)
    {
        if(is_array($options)) {
            $this->setOptions($options);
        }
        try {
            $this->pdo = new PDO('mysql:host='.$this->hostname.';dbname='.$this->database, $this->username, $this->password);
        } catch(PDOException $e) {
            die($e->getMessage());
        }
    }
    
    /**
     * Set database object options from an array.
     *
     * @param array $options
     * @return WLP_Db_Mysql
     */
    public function setOptions($options)
    {
        foreach ($options as $key => $value) {
            $normalized = ucfirst($key);
            $method = 'set' . $normalized;
            if (method_exists($this, $method)) {
                $this->$method($value);
            } else {
                throw new Exception('Setter method for option "'.$key.'" does not exsist.');
            }
        }
        
        return $this;
    }
    
    /**
     * Inserts a single item to the database.
     *
     * @param string $table Table to save the item to
     * @param array $item Array with the rows of data
     * @return integer|bool Returns last insert id if successful or false if not
     */
    public function insertItem($table, $item)
    {
        if(!is_string($table)) {
            throw new Exception('Table argument should be a string.');
        }
        if(!is_array($item)) {
            throw new Exception('Item argument should be an array.');
        }
        $columns = array_keys($item);
        $params = $columns;
        array_walk($params, array($this, "appendColon"));
        $statmentString = 'Insert Into '.$table.' ('.implode(', ', $columns).') Values ('.implode(', ', $params).')';
        $this->statement = $this->pdo->prepare($statmentString);
        
        $columnCount = count($columns);
        for($i = 0; $i < $columnCount; $i++) {
            $this->statement->bindParam($params[$i], $item[$columns[$i]]);
        }
        if($this->statement->execute()) {
            return $this->pdo->lastInsertId();
        }
        return false;
    }
    
    /**
     * Inserts multiple items to a database.
     * 
     * @param string $table Table to save the items to
     * @param array $items Zero indexed array containing items and their rows of data
     * @return bool Returns true or false depending if the inserts was successful
     */
    public function insertItems($table, $items)
    {
        if(!is_string($table)) {
            throw new Exception('Table argument should be a string.');
        }
        if(!is_array($items)) {
            throw new Exception('Items argument should be an array.');
        }
        $columns = array_keys($items[0]);
        $params = $columns;
        array_walk($params, array($this, "appendColon"));
        $statmentString = 'Insert Into '.$table.' ('.implode(', ', $columns).') Values ('.implode(', ', $params).')';
        $this->statement = $this->pdo->prepare($statmentString);
        
        $columnCount = count($columns);
        foreach($items as $item) {
            for($i = 0; $i < $columnCount; $i++) {
                $this->statement->bindParam($params[$i], $item[$columns[$i]]);
            }
            if(!$this->statement->execute()) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * Gets a single item from the database.
     *
     * @param string $table Table to get item from
     * @param array $columns Array of columns to get
     * @param string $where Optional where statement
     * @return array|bool Result of the query or false if no results where found
     */
    public function getItem($table, $columns, $where = '')
    {
        if(!is_string($table)) {
            throw new Exception('Table argument should be a string.');
        }
        if(!is_array($columns)) {
            throw new Exception('Columns argument should be an array.');
        }
        if(!is_string($where)) {
            throw new Exception('Where argument should be a string.');
        }
        $statementString = 'Select '.implode(', ', $columns).' From '.$table.' ' . ($where ? 'Where ' . $where : '') . ' Limit 1';
        if($this->statement = $this->pdo->query($statementString)) {
            return $this->statement->fetch(PDO::FETCH_ASSOC);
        }
        return false;
    }
    
    /**
     * Gets multiple items from a database.
     *
     * @param string $table Table to get items from
     * @param array $columns Array of columns to get
     * @param string $where Optional where statement
     * @return array|bool Result of the query or false if non where found
     */
    public function getItems($table, $columns, $where = '')
    {
        if(!is_string($table)) {
            throw new Exception('Table argument should be a string.');
        }
        if(!is_array($columns)) {
            throw new Exception('Columns argument should be an array.');
        }
        if(!is_string($where)) {
            throw new Exception('Where argument should be a string.');
        }
        $statementString = 'Select '.implode(', ', $columns).' From '.$table.' ' . ($where ? 'Where ' . $where : '');
        
        if($this->statement = $this->pdo->query($statementString)) {
            return $this->statement->fetchAll(PDO::FETCH_ASSOC);
        }
        return false;
    }
    
    /**
     * Sets the hostname for the Mysql connection.
     *
     * @param string $hostname
     * @return WLP_Db_Mysql
     */
    public function setHostname($hostname)
    {
        if(is_string($hostname)) {
            $this->hostname = $hostname;
            return $this;
        }
        throw new Exception('Provided argument for method '.__METHOD__.' is not valid');
    }
    
    /**
     * Gets the hostname for the Mysql connection.
     *
     * @return string
     */
    public function getHostname()
    {
        return $this->hostname;
    }
    
    /**
     * Sets the username for the Mysql connection.
     *
     * @param string $username
     * @return WLP_Db_Mysql
     */
    public function setUsername($username)
    {
        if(is_string($username)) {
            $this->username = $username;
            return $this;
        }
        throw new Exception('Provided argument for method '.__METHOD__.' is not valid');
    }
    
    /**
     * Gets the username for the Mysql connection.
     *
     * @return string
     */
    public function getUsername()
    {
        return $this->username;
    }
    
    /**
     * Sets the password for the Mysql connection.
     *
     * @param string $hostname
     * @return WLP_Db_Mysql
     */
    public function setPassword($password)
    {
        if(is_string($password)) {
            $this->password = $password;
            return $this;
        }
        throw new Exception('Provided argument for method '.__METHOD__.' is not valid');
    }
    
    /**
     * Gets the password for the Mysql connection.
     *
     * @return string
     */
    public function getPassword()
    {
        return $this->password;
    }
    
    /**
     * Sets the database for the Mysql connection.
     *
     * @param string $database
     * @return WLP_Db_Mysql
     */
    public function setDatabase($database)
    {
        if(is_string($database)) {
            $this->database = $database;
            return $this;
        }
        throw new Exception('Provided argument for method '.__METHOD__.' is not valid');
    }
    
    /**
     * Gets the database for the Mysql connection.
     *
     * @return string
     */
    public function getDatabase()
    {
        return $this->database;
    }
    
    /**
     * Quotes variables for use in SQL strings.
     *
     * @param string $string String to be quoted
     * @return string Quoted string
     */
    public function quote($string)
    {
        return $this->pdo->quote($string);
    }
    
    /**
     * Appends a colon to the provided string.
     *
     * @param string $string
     * @return string
     */
    protected function appendColon(&$string, $key)
    {
        if(!is_string($string)) {
            throw new Exception('Provided argument is not a string.');
            return false;
        }
        $string = ':' . $string;
    }
}